package co.baiku.boot.config;

import co.baiku.boot.cache.type.CacheEngine;
import co.baiku.boot.common.tools.StringTools;
import co.baiku.boot.shiro.ShiroCacheManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collection;

@Component

@ConfigurationProperties(prefix = "ajavaer.shiro")
@ConditionalOnProperty("ajavaer.shiro.realm")
@AutoConfigureBefore(RedisAutoConfiguration.class)
public class ShiroConfig implements InitializingBean, ApplicationContextAware {

    private CacheEngine cacheEngine;
    @NestedConfigurationProperty
    private ShiroFilterChain filterChainDefinition;
    private String loginUrl;
    private String successUrl;
    private String unauthorizedUrl;
    private String realm;
    private String sessionManager;
    private ApplicationContext applicationContext;
    private String cachePrefix;
    private DefaultWebSessionManager webSessionManager;
    private ShiroCacheManager shiroCacheManager;
    private Collection<Realm> authorizingRealm = new ArrayList<>();
    @Resource
    private RedisConnectionFactory redisConnectionFactory;

    public RedisTemplate<String, Object> redisTemplate() {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
        redisTemplate.setHashValueSerializer(new JdkSerializationRedisSerializer());
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        shiroCacheManager = new ShiroCacheManager();
        shiroCacheManager.init(this);
        for (String item : realm.split(StringTools.COMMA)) {
            authorizingRealm.add((AuthorizingRealm) applicationContext.getBean(item));
        }
        if (StringTools.isNotBlank(sessionManager)) {
            webSessionManager = (DefaultWebSessionManager) applicationContext.getBean(sessionManager);
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    public CacheEngine getCacheEngine() {
        return cacheEngine;
    }

    public void setCacheEngine(CacheEngine cacheEngine) {
        this.cacheEngine = cacheEngine;
    }

    public ShiroFilterChain getFilterChainDefinition() {
        return filterChainDefinition;
    }

    public void setFilterChainDefinition(ShiroFilterChain filterChainDefinition) {
        this.filterChainDefinition = filterChainDefinition;
    }

    public String getRealm() {
        return realm;
    }

    public ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    public String getLoginUrl() {
        return loginUrl;
    }

    public void setLoginUrl(String loginUrl) {
        this.loginUrl = loginUrl;
    }

    public String getSuccessUrl() {
        return successUrl;
    }

    public void setSuccessUrl(String successUrl) {
        this.successUrl = successUrl;
    }

    public String getUnauthorizedUrl() {
        return unauthorizedUrl;
    }

    public void setUnauthorizedUrl(String unauthorizedUrl) {
        this.unauthorizedUrl = unauthorizedUrl;
    }

    public void setRealm(String realm) {
        this.realm = realm;
    }

    public Collection<Realm> getAuthorizingRealm() {
        return authorizingRealm;
    }

    public void setAuthorizingRealm(Collection<Realm> authorizingRealm) {
        this.authorizingRealm = authorizingRealm;
    }

    public ShiroCacheManager getShiroCacheManager() {
        return shiroCacheManager;
    }

    public void setShiroCacheManager(ShiroCacheManager shiroCacheManager) {
        this.shiroCacheManager = shiroCacheManager;
    }

    public String getCachePrefix() {
        return cachePrefix;
    }

    public void setCachePrefix(String cachePrefix) {
        this.cachePrefix = cachePrefix;
    }

    public String getSessionManager() {
        return sessionManager;
    }

    public void setSessionManager(String sessionManager) {
        this.sessionManager = sessionManager;
    }

    public DefaultWebSessionManager getWebSessionManager() {
        return webSessionManager;
    }

    public void setWebSessionManager(DefaultWebSessionManager webSessionManager) {
        this.webSessionManager = webSessionManager;
    }
}
